from typing import TypeVar, Generic, Dict
from abc import ABC, abstractmethod
import json
from services.storage import AioRedisCache

T = TypeVar('T')

class UserSchema(ABC, Generic[T]):
    @abstractmethod
    async def get_by_email(self, email:str, /, defValue:T|None)->T|None:
        pass
    
    @abstractmethod
    async def save(self, user:T)->None:
        pass
    
    @abstractmethod
    async def exists(self, email:str)->bool:
        pass
    
    @abstractmethod
    async def close(self)->None:
        pass
    
class RedisUserSchema(UserSchema[Dict[str,str]]):
    def __init__(self, client:AioRedisCache) -> None:
        self.__db_client = client
        
    async def get_by_email(self, email:str, /, defValue:Dict[str,str]|None)->Dict[str,str]|None:
        user_json_str = await self.__db_client.get_key(email, None)
        if user_json_str is None:
            return defValue
        
        return dict(json.loads(user_json_str.decode('utf-8')))
    
    async def save(self, user:Dict[str,str])->None:
        await self.__db_client.set_key(key=user['email'], value=json.dumps(user), tts_seconds=None)
    
    async def exists(self, email:str)->bool:
        return await self.__db_client.exist_key(email)
    
    def redis_client(self)->AioRedisCache:
        return self.__db_client
    
    async def close(self)->None:
        self.__db_client = None